CanvasRenderingContext2D.prototype.lineToVec = function({x, y}){
  this.lineTo(x, y);
}

CanvasRenderingContext2D.prototype.moveToVec = function({x, y}){
  this.moveTo(x, y);
}

CanvasRenderingContext2D.prototype.bezierCurveToVec = function(cv1, cv2, ev){
  this.bezierCurveTo(cv1.x, cv1.y, cv2.x, cv2.y, ev.x, ev.y);
}


CanvasRenderingContext2D.prototype.point = function(v, {fillStyle='#000', radius=1.7}={}){

  if (v != undefined){
      let dpr = window.devicePixelRatio,
          ratio = this.canvas.height/2/dpr;
  
      this.fillStyle = fillStyle;
      this.beginPath()
      this.arc(v.x*ratio, v.y*ratio, radius, 0, Math.PI*2);
      this.fill();
  }
}

CanvasRenderingContext2D.prototype.drawVecs = function(vecs, {withPoint=false, lineWidth=1, strokeStyle, fillStyle, drawBezier=false, drawControl=false}={}){

  let dpr = window.devicePixelRatio,
      ratio = this.canvas.height/2/dpr;

  const points = vecs.map(({x, y}) => ({
    x: x * ratio,
    y: y * ratio
  }))

  this.lineWidth = lineWidth;

  this.lineCap = 'round';
  this.lineJoin = 'round';

  
  this.strokeStyle = strokeStyle ?? vecs.strokeStyle;
  this.fillStyle = fillStyle ?? vecs.fillStyle;
  
  try {

    this.beginPath();
    if (drawBezier) {
      for (let i = 0; i < points.length; i+=4){
        this.moveToVec(points[i]);
        this.bezierCurveToVec(points[i+1], points[i+2], points[i+3]);
      }
    } else {
      const [first, ...rest] = points;
      this.moveToVec(first);
      for (let i = 0; i < rest.length; i++){
        this.lineToVec(rest[i]);
      }
    }
    if (vecs.isClosure()) {
      this.closePath();
    } 
    if (vecs.strokeStyle ?? strokeStyle) {
      this.stroke();
    }
    if (vecs.fillStyle ?? fillStyle) {
      this.fill();
    }

    if (drawControl) {
      for (let i = 0; i < points.length; i+=4){
        this.moveToVec(points[i]);
        this.lineToVec(points[i+1]);
        this.moveToVec(points[i+2]);
        this.lineToVec(points[i+3]);
      }
      this.stroke();
    }

  } catch (err){
    console.warn(err);
  }

  if (withPoint) {
    for (let i = 0; i < vecs.length; i++) {
      this.point(vecs[i]);
    }
  }

}

CanvasRenderingContext2D.prototype.drawOutline = function(polys, sects) {

  for (let poly of polys) {
    this.drawVecs(poly, {lineWidth: 1, strokeStyle:'#000'})
  }

  for (let sect of sects) {
    this.drawVecs(sect, {lineWidth: 1, strokeStyle:'#000'})
  }
}

CanvasRenderingContext2D.prototype.drawPoly = function(poly, fillColor) {
  
  this.drawVecs(poly, {fillStyle: fillColor ?? randColor(0.05)});

}

CanvasRenderingContext2D.prototype.text = function(text, vec, {fontSize=10, fillStyle='#000'}={}){

  this.save();
  this.fillStyle = fillStyle;
  this.font = `${fontSize}px Helvetica`;
  this.textAlign = 'center';
  this.textBaseline = 'middle';
  if (vec != undefined){
      let dpr = window.devicePixelRatio,
          ratio = this.canvas.height/2/dpr;
  
      this.fillText(text, vec.x*ratio, vec.y*ratio);
  }
  this.restore();
}
